package com.enation.app.javashop.consumer.shop.goods;

import com.enation.app.javashop.consumer.core.event.OrderStatusChangeEvent;
import com.enation.app.javashop.consumer.core.event.RefundStatusChangeEvent;
import com.enation.app.javashop.consumer.core.event.TradeIntoDbEvent;
import com.enation.app.javashop.core.aftersale.model.dos.RefundDO;
import com.enation.app.javashop.core.aftersale.model.dos.RefundGoodsDO;
import com.enation.app.javashop.core.aftersale.model.enums.RefundStatusEnum;
import com.enation.app.javashop.core.aftersale.model.enums.RefuseTypeEnum;
import com.enation.app.javashop.core.base.message.OrderStatusChangeMsg;
import com.enation.app.javashop.core.base.message.RefundChangeMsg;
import com.enation.app.javashop.core.client.goods.GoodsQuantityClient;
import com.enation.app.javashop.core.client.trade.AfterSaleClient;
import com.enation.app.javashop.core.client.goods.GoodsClient;
import com.enation.app.javashop.core.goods.model.enums.QuantityLogType;
import com.enation.app.javashop.core.goods.model.vo.GoodsQuantityVO;
import com.enation.app.javashop.core.goods.service.GoodsQuantityManager;
import com.enation.app.javashop.core.trade.cart.model.vo.CartSkuVO;
import com.enation.app.javashop.core.trade.order.model.dos.OrderDO;
import com.enation.app.javashop.core.trade.order.model.dto.OrderDTO;
import com.enation.app.javashop.core.trade.order.model.enums.OrderStatusEnum;
import com.enation.app.javashop.core.trade.order.model.enums.PayStatusEnum;
import com.enation.app.javashop.core.trade.order.model.enums.PaymentTypeEnum;
import com.enation.app.javashop.core.trade.order.model.enums.ShipStatusEnum;
import com.enation.app.javashop.core.trade.order.model.vo.OrderSkuVO;
import com.enation.app.javashop.core.trade.order.model.vo.TradeVO;
import com.enation.app.javashop.core.client.trade.OrderClient;
import com.enation.app.javashop.core.trade.sdk.model.OrderDetailDTO;
import com.enation.app.javashop.framework.exception.ResourceNotFoundException;
import com.enation.app.javashop.framework.util.JsonUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.List;

/**
 * 商品库存增加/扣减
 *
 * @author fk
 * @version v1.0
 * @since v7.0.0
 * 2018年6月22日 上午10:18:20
 */
@Service
public class GoodsQuantityChangeConsumer implements OrderStatusChangeEvent, RefundStatusChangeEvent, TradeIntoDbEvent {

    @Autowired
    private GoodsQuantityClient goodsQuantityClient;

    @Autowired
    private AfterSaleClient afterSaleClient;

    @Autowired
    private OrderClient orderClient;

    private final Logger logger = LoggerFactory.getLogger(getClass());


    /**
     * 订单变化处理
     *
     * @param orderMessage
     */
    @Override
    public void orderChange(OrderStatusChangeMsg orderMessage) {
        //发货
        if (orderMessage.getNewStatus().name().equals(OrderStatusEnum.SHIPPED.name())) {
            //获取订单信息
            OrderDO order = orderMessage.getOrderDO();
            String itemsJson = order.getItemsJson();
            //订单中的sku集合
            List<OrderSkuVO> list = JsonUtil.jsonToList(itemsJson, OrderSkuVO.class);
            List<GoodsQuantityVO> quantityVOList = new ArrayList<>();
            for (OrderSkuVO sku : list) {
                GoodsQuantityVO goodsQuantity = new GoodsQuantityVO();
                goodsQuantity.setEnableQuantity(0);
                goodsQuantity.setGoodsId(sku.getGoodsId());
                goodsQuantity.setQuantity(sku.getNum());
                goodsQuantity.setSkuId(sku.getSkuId());
                quantityVOList.add(goodsQuantity);
            }
            //扣减库存
            goodsQuantityClient.reduceGoodsQuantity(order.getSn(), QuantityLogType.SHIP, quantityVOList);

        }
        //付款前 订单取消
        if (orderMessage.getNewStatus().name().equals(OrderStatusEnum.CANCELLED.name()) && orderMessage.getOrderDO().getPayStatus().equals(PayStatusEnum.PAY_NO.name())) {
            OrderDO order = orderMessage.getOrderDO();
            String itemsJson = order.getItemsJson();
            List<OrderSkuVO> list = JsonUtil.jsonToList(itemsJson, OrderSkuVO.class);
            for (OrderSkuVO sku : list) {
                GoodsQuantityVO goodsQuantity = new GoodsQuantityVO();
                goodsQuantity.setEnableQuantity(sku.getNum());
                goodsQuantity.setGoodsId(sku.getGoodsId());
                goodsQuantity.setQuantity(0);
                goodsQuantity.setSkuId(sku.getSkuId());
                //增加库存
                goodsQuantityClient.addGoodsQuantity(order.getSn(), goodsQuantity, QuantityLogType.ORDER_CANCEL);
            }
        }

    }

    @Override
    public void refund(RefundChangeMsg refundChangeMsg) {
        RefundDO refund = refundChangeMsg.getRefund();
        //获取当前订单信息
        OrderDetailDTO orderDetailDTO = orderClient.getModel(refundChangeMsg.getRefund().getOrderSn());
        //退款 当商家审核已通过且未发货 增加可用库存
        boolean bool = refund.getRefuseType().equals(RefuseTypeEnum.RETURN_MONEY.name()) && orderDetailDTO.getShipStatus().equals(ShipStatusEnum.SHIP_NO.name()) && refundChangeMsg.getRefundStatusEnum().name().equals(RefundStatusEnum.PASS.name());
        List<RefundGoodsDO> goodsList = afterSaleClient.getRefundGoods(refund.getSn());
        if (bool) {
            for (RefundGoodsDO goods : goodsList) {
                // 商品入库
                GoodsQuantityVO goodsQuantity = new GoodsQuantityVO();
                goodsQuantity.setSkuId(goods.getSkuId());
                goodsQuantity.setGoodsId(goods.getGoodsId());
                goodsQuantity.setEnableQuantity(goods.getReturnNum());
                goodsQuantity.setQuantity(0);
                //增加库存
                goodsQuantityClient.addGoodsQuantity(refund.getOrderSn(), goodsQuantity, QuantityLogType.ORDER_CANCEL);

            }
        }
        //退货且订单入库，增加库存
        bool = refund.getRefuseType().equals(RefuseTypeEnum.RETURN_GOODS.name()) && refundChangeMsg.getRefundStatusEnum().equals(RefundStatusEnum.STOCK_IN);
        if (bool) {
            for (RefundGoodsDO goods : goodsList) {
                // 商品入库
                GoodsQuantityVO goodsQuantity = new GoodsQuantityVO();
                goodsQuantity.setSkuId(goods.getSkuId());
                goodsQuantity.setGoodsId(goods.getGoodsId());
                goodsQuantity.setEnableQuantity(goods.getReturnNum());
                goodsQuantity.setQuantity(goods.getReturnNum());
                //增加库存
                goodsQuantityClient.addGoodsQuantity(refund.getOrderSn(), goodsQuantity, QuantityLogType.ORDER_CANCEL);

            }
        }


    }

    /**
     * 处理订单创建扣减库存
     *
     * @param tradeVO
     */
    @Override
    public void onTradeIntoDb(TradeVO tradeVO) {
        if (tradeVO == null) {
            throw new ResourceNotFoundException("交易不存在");
        }
        //获取交易中的订单集合
        List<OrderDTO> orderDTOS = tradeVO.getOrderList();
        List<GoodsQuantityVO> goodsQuantityVOList = new ArrayList<>();
        //此变量标识订单是否全部更新成功，只有订单状态全部更新成功，交易状态才可以更新为已确认，只要有一个订单更新状态失败，则交易失败
        boolean bool = true;
        int i = 0;
        for (OrderDTO order : orderDTOS) {
            //获取订单中的sku信息
            List<CartSkuVO> skuList = order.getSkuList();
            for (CartSkuVO sku : skuList) {
                GoodsQuantityVO goodsQuantity = new GoodsQuantityVO();
                goodsQuantity.setSkuId(sku.getSkuId());
                goodsQuantity.setGoodsId(sku.getGoodsId());
                goodsQuantity.setEnableQuantity(sku.getNum());
                goodsQuantity.setQuantity(0);
                goodsQuantityVOList.add(goodsQuantity);
            }
            //扣减库存
            goodsQuantityClient.reduceGoodsQuantity(order.getSn(), QuantityLogType.ORDER_CREATE, goodsQuantityVOList);
            OrderStatusEnum status = OrderStatusEnum.CONFIRM;
            //如果代支付金额为0，则状态变成已付款
            if (order.getNeedPayMoney() == 0&&!order.getPaymentType().equals(PaymentTypeEnum.COD.value())) {
                status = OrderStatusEnum.PAID_OFF;
            }
            //如果订单状态更新失败，重试三次，如果最终失败则回滚库存，成功后误操作
            if (!this.updateState(order.getSn(), 0, status)) {
                bool = false;
                //回滚库存
                goodsQuantityClient.rollbackReduce(order.getSn());
                //更新订单状态为出库失败
                orderClient.updateOrderStatus(order.getSn(), OrderStatusEnum.INTODB_ERROR);
            }
            i++;
        }
        //处理交易,如果此交易中有一个订单状态更新失败，则此交易状态为出库失败
        if (!bool) {
            this.updateTradeState(tradeVO.getTradeSn(), 0, OrderStatusEnum.INTODB_ERROR);
        } else {
            this.updateTradeState(tradeVO.getTradeSn(), 0, OrderStatusEnum.CONFIRM);
        }

    }

    /**
     * 修改订单状态
     *
     * @param sn    订单sn
     * @param times 次数
     * @return 是否修改成功
     */
    private boolean updateState(String sn, Integer times, OrderStatusEnum status) {
        try {
            //失败三次后直接返回
            if (times >= 3) {
                logger.error("订单状态重试三次后更新失败,交易号为" + sn + ",重试");
                return false;
            }
            //更改订单状态为已确认
            if (!orderClient.updateOrderStatus(sn, status)) {
                //如果更新失败，则等待1秒重试
                Thread.sleep(1000);
                return updateState(sn, ++times, status);
            } else {
                return true;
            }
        } catch (Exception e) {
            logger.error("订单状态更新失败,订单号为" + sn + ",重试" + ++times + "次,消息" + e.getMessage());
            updateState(sn, ++times, status);
        }
        return true;
    }


    /**
     * 修改订单状态
     *
     * @param sn          订单sn
     * @param times       次数
     * @param orderStatus 订单状态
     * @return 是否修改成功
     */
    private boolean updateTradeState(String sn, Integer times, OrderStatusEnum orderStatus) {
        try {
            //失败三次后直接返回
            if (times >= 3) {
                logger.error("交易状态重试三次后更新失败,交易号为" + sn + ",重试");
                return false;
            }
            //更改交易状态为已确认
            if (!orderClient.updateTradeStatus(sn, orderStatus)) {
                //如果更新失败，则等待1秒重试
                Thread.sleep(1000);
                return updateTradeState(sn, ++times, orderStatus);
            } else {
                return true;
            }
        } catch (Exception e) {
            logger.error("交易状态更新失败,订单号为" + sn + ",重试" + ++times + "次,消息" + e.getMessage());
            updateState(sn, ++times, orderStatus);
        }
        return false;
    }
}
